package net.freestu.sola.web.parser.Parse;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.freestu.sola.web.spider.ballerina.myUtil.URLUtil;
import net.freestu.sola.web.spider.ballerina.myUtil.URLUtilFactory;
import net.freestu.sola.web.spider.urlfilter.LinkFilter;
import net.freestu.sola.web.spider.urlfilter.LinksForbider;
import net.freestu.sola.web.spider.urlfilter.MyLink;
import net.freestu.sola.web.spider.urlfilter.NewPostfixFilter;
import net.freestu.sola.web.spider.urlfilter.WebFilter;
import net.freestu.sola.web.util.MyProperty;
import net.freestu.sola.web.util.TagOperator;

/**
 * 接受html文件，然后获取一个Page对象。
 * 
 * @author 秋刀鱼的滋味
 * 
 */
public class PageParser {

	private File htmlfile;// 接受Html文件，转化位Page对象。

	private Page page;

	// --------Page对象属性-------
	private String id;

	private String school;

	private String url;

	private String redirect;

	private String title;

	private String update;

	private String links;

	private String content;

	private String score;

	// -------------------------

	// ------一些工具对象,在中间过程起作用------
	private MyProperty infos;// 下载后的网页头部自定义信息。

	private String initpage;// 除去网页头部信息的网页内容。

	private String head; // head标签内容。

	private String body; // body 标签。

	private URLUtil pagelinks = URLUtilFactory.getURLUtil("HashSet");

	private String puretext;

	// -------------------------

	public PageParser(File htmlfile, String id, String school) {

		this.htmlfile = htmlfile;
		this.id = id;
		this.school = school;
		init();// 初始化
	}

	public Page getPage() {

		System.out.println("----------------------------------------------");
		System.out.println(Thread.currentThread().getName()+":正在解析-->"+htmlfile);//
		init();
		pickAll();
		
		
		page = new Page(id, school, url, redirect, title, update, links,
				content, score);
		System.out.println(Thread.currentThread().getName()+":解析完毕-->"+url);//
		System.out.println();
		return page;
	}

	private void pickUrl() {
		url = cut(infos.getPro("Url"));

	}

	private void pickRedirect() {
		redirect = cut(infos.getPro("Redirect"));
	}

	private void pickTitle() {

		if (head == null)
			title = null;

		ArrayList al = TagOperator.digContentOfTag("<title>", "</title>", head);

		if (al == null) {
			title = "   ";
			return;
		}
		Iterator it = al.iterator();
		while (it.hasNext()) {
			title = (String) it.next();
		}
	}

	private void pickUpdate() {
		update = infos.getPro("Date");
	}

	private void pickLinks() {

		
		setLinks();
		StringBuffer str = new StringBuffer("");
		Iterator it = pagelinks.urlIterator();
		while (it.hasNext()) {
			str.append(it.next() + "\\");
		}
		links = str.toString();

	}

	private void pickContent() {

		if(puretext==null){
			content=" ";
		}else{
		  content = puretext;
		}
	}

	private void pickScore() {
		score = infos.getPro("InitScore");
	}

	private void init() {

		setInfo();// 先设计好info信息。
		initPage();// 将html页面变成String。
		//pickHead();
		//pickBody();
		//pickLinks();
		//toPureText();

	}

	/**
	 * 提取标签<head></head>的内容。
	 * 
	 */
	private void pickHead() {

		ArrayList al = TagOperator.digContentOfTag("<head>", "</head>",
				initpage);

		if (al == null) {
			head = null;// 如果没有出来，则设定为null
			return;
		}

		Iterator it = al.iterator();

		while (it.hasNext()) {

			head = (String) it.next();
		}
	}

	/**
	 * 提取网页中的<body>部分。OK!
	 * 
	 */
	public void pickBody() {

		/**
		 * 这个地方对其做出忽略处理，哈哈，我简直太有才啦。
		 */
		ArrayList al = TagOperator.digContentOfTag("<body>", "</body>",
				initpage);

		if (al == null) {
			body = "";
			return;
		}

		Iterator it = al.iterator();
		while (it.hasNext()) {
			body = (String) it.next();
		}
	}

	private void pickAll() {

		pickHead();
		pickBody();
		pickUrl();
		pickRedirect();
		pickTitle();
		pickUpdate();
		pickLinks();
		pickScore();
		//----------
		toPureText();//变成纯文本后可以提取纯文字。
		pickContent();
		
	}

	private void setInfo() {
		try {
			
			//if(htmlfile)
			FileReader fr = new FileReader(htmlfile); // 创建一个FileReader对象 从磁盘读
			BufferedReader br = new BufferedReader(fr); // 创建一个BufferedReader对象

			StringBuffer line = new StringBuffer();
			String sss = "";
			while (br.ready()) { // 如果文件准备好，就继续读
				sss = br.readLine();
				if (sss.equals("---------------------"))
					break;
				line.append(sss); // 读一行
			}
			infos = new MyProperty(line.toString());
			infos.map();

			br.close(); // 关闭流
			fr.close(); // 关闭流
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * 网页除去报头后转表成String. 初始化网页。
	 */
	private void initPage() {

		try {
			FileReader fr = new FileReader(htmlfile);
			BufferedReader br = new BufferedReader(fr);

			int size = infos.getNum();

			for (int i = 0; i <= size; i++) {
				br.readLine();// 将网页的自定义头部去掉了。
			}

			StringBuilder sb = new StringBuilder();
			while (br.ready()) {
				sb.append(br.readLine());
			}
			initpage = sb.toString();
			if (initpage == null || initpage.trim().equals(""))
				initpage = "这张页面没有信息";

			br.close();
			fr.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	// ----以下全是内部隐藏的信息---------------------
	// -------------------------------------------

	public void setLinks() {

		String regex = "[\"|'](http://)?(([\\w-]+\\.)+[\\w-]+)?(/[\\w- ./?%&=]*)?[\"|']";
		Pattern pt = Pattern.compile(regex);
		Matcher mt = pt.matcher(initpage);
		// String seedname = "";
		
		ArrayList al1 = new ArrayList();// 10.10修改
		while (mt.find()) {
			String str = mt.group();
			al1.add(str);// 初始链接，还没有进行处理。
		}
		ArrayList al2 = pickUrlWithHref(TagOperator.digSingleTag("a", initpage));
		ArrayList allLink;
		// !!!这个地方需要对这些进行是否为空的判断！！！
		if (al2 != null) {
			al2.addAll(al1);
			allLink = al2;
		} else {
			allLink = al1;
		}

		// ---将这个页面的的地址和重定向放人Hash表中。
		String url = cut(infos.getPro("Url"));
		String rrr = cut(infos.getPro("Redirect"));
		// ------------

		Iterator itoflinks = allLink.iterator();
		while (itoflinks.hasNext()) {
			String str = simpleFiter((String) itoflinks.next());// 主要是将一些地址进行规范，将相对地址转化为绝对地址。和对地址进行规范
			str = complexFilter(str);

			if (str == null)
				continue;

			// 自己的页面中不能出现自己本身的链接。
			if (cut(str).equals(cut(url)) || cut(str).equals(cut(url))) {
				continue;
			}

			if (str != null) { // 初级过滤可能返回null

				pagelinks.addURL(cut(str));// 这里规范一下，后面都没有/
			}
		}

	}

	public String complexFilter(String str) {

		String url = infos.getPro("Url");

		URL u;
		try {
			u = new URL(url);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}

		String name = u.getHost().replaceFirst("(www.)?", "");

		// 这里怎么没有对IPFilter进行过滤呢??

		MyLink ml = new MyLink(str);
		LinkFilter lfb = new LinksForbider(ml);
		LinkFilter pf = new NewPostfixFilter(lfb);// 按照后缀名过滤。
		LinkFilter wf = new WebFilter(pf, name);// 按照站点过滤。!!!这个地方以后需要动态分配。
		// LinkFilter ctf=new
		// ContentTypeFilter(wf);//按照报头中content-type,这个还可以过滤掉没有连接的URL.

		String ss = wf.getLinkAfterFilter();

		if (ss != null) {
			return ss;
		} else {
			return null;
		}
	}

	private String simpleFiter(String str) {
		

		if (str == null)
			return null;// 过滤。
		String redirect = infos.getPro("Redirect");
		str = str.replaceAll("\"|'|\\|", "");// 1.将| " ' 替换成没东西。
		str = str.replace("\\", "");// 将斜杠去掉 \"http:dddd\"
		if (str.replace(" ", "").equals(""))
			return null;
		
		// 第一重过滤
		if (str.startsWith("#") || str.endsWith("=")
				|| str.toLowerCase().startsWith("javascript:")
				|| str.toLowerCase().startsWith("mailto:")) {
			// 如果这个是"http://www.ii.com/id="这种肯定不行啊？
			// 由于这个地方的#是锚点的意思。只是在当前页面进行跳转。所以没有收录的必要。
			return null;
		}
		
		int f=str.indexOf("#");
		if(f!=-1){//这个地方是为了将http://www.sina.com#11 这种进行排除。
			str=str.substring(0,f);
		}
		
		if (str.toLowerCase().startsWith("http://")) {
			return str;
		} else {
			if (-1 != str.indexOf("?")) {
				return constructUrl(str, redirect, true);
			} else {
				return constructUrl(str, redirect, false);
			}
		}
	}

	public String constructUrl(String link, String base, boolean strict) {
		try {
			String path;
			boolean modified;
			boolean absolute;
			int index;
			URL url=null; // constructed URL combining relative link and base

			// Bug #1461473 Relative links starting with ?
			if (!strict && ('?' == link.charAt(0))) { // remove query part of
				// base if any
				if (-1 != (index = base.lastIndexOf('?')))
					base = base.substring(0, index);
				url = new URL(base + link);
			} else
				
				try {
					url = new URL(new URL(base), link);
				} catch (java.net.MalformedURLException e) {
					return null;//unknown protocol: mhtml
					            //这里是处理这个异常。
				}
			   path = url.getFile();


			modified = false;
			absolute = link.startsWith("/");
			if (!absolute) { // we prefer to fix incorrect relative links
				// this doesn't fix them all, just the ones at the start
				while (path.startsWith("/.")) {
					if (path.startsWith("/../")) {
						path = path.substring(3);
						modified = true;
					} else if (path.startsWith("/./") || path.startsWith("/.")) {
						path = path.substring(2);
						modified = true;
					} else
						break;
				}
			}
			// fix backslashes
			while (-1 != (index = path.indexOf("/\\"))) {
				path = path.substring(0, index + 1) + path.substring(index + 2);
				modified = true;
			}
			if (modified)
				url = new URL(url, path);

			return (url.toString());
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 处理<body>中的字符串，将标签去掉后，全部是纯文本。 除去 Html标签。
	 */
	public void toPureText() {

		
		
		if (body == null) {
			puretext =null;
			return;
		}

		String ss = htmlToStr(body).trim();// 去掉HTML标签。

		
		String sss;
		// 这个地方统一把一些特殊字符去掉。
		try {
			// ???这个地方去掉了一些转义字符。\\s匹配\\r,\\n,\\r和空格等。
			// 这个地方以后可以再扩充。
			sss = ss.replaceAll("\\r", "").replaceAll("\\n", "").replaceAll(
					"\\b", "").replaceAll("\\?", "").replaceAll(":", "")
					.replaceAll(";", "");
			/*
			 * .replaceAll("&amp","").replaceAll("&nbsp","").replaceAll("&lt",
			 * "").replaceAll("&gt","").replaceAll("&quot","").replaceAll("&reg" \\
			 * ,"").replaceAll("&copy","").replaceAll("&trade","").replaceAll("&ensp","").replaceAll("&emsp","");
			 */

			// filtrate(sss);//将网页进行彻底的过滤。
		} catch (java.lang.NullPointerException e) {
			e.printStackTrace();
			sss = null;
		}
		puretext = sss.trim();
	}

	/**
	 * 从网上找的一个算法，除去HTML标签.这个是除去标签的主要算法。
	 * 
	 * @param htmlStr
	 * @return
	 */
	public String htmlToStr(String htmlStr) {

		String result = "";
		boolean flag = true;

		if (htmlStr == null) {// 容错性
			return null;
		}

		// 这里将&nbsp变成空格比较好，这里就不影响英文分词了。
		htmlStr = htmlStr.replace("\"", "").replace("&nbsp", " ").replace(
				"&bull;", "").replace("&gt", "").replace("&copy", "").replace(
				"&ensp", "").replace("&lt", "").replace("&trade", "").replace(
				"&emsp", "").replace("&rsaquo","").replace("&lsaquo",""); // 去掉引号

		// 去掉HTML中的<script>脚本------------------

		ArrayList al=null;
		try {
			al = TagOperator.digContentOfTag("<script>", "</script>",
					htmlStr);
		} catch (StringIndexOutOfBoundsException e) {
		}

		if (al != null) {// 容错性
			Iterator it = al.iterator();

			while (it.hasNext()) {

				String str = (String) it.next();

				htmlStr = htmlStr.replace(str, "");
			}
		}
		// ------------------------------

		char[] a = htmlStr.toCharArray();
		int length = a.length;
		for (int i = 0; i < length; i++) {
			if (a[i] == '<') {
				flag = false;
				continue;
			}
			if (a[i] == '>') {
				flag = true;
				continue;
			}
			if (flag == true) {
				result += a[i];
			}
		}

		return result.toString();
	}

	/**
	 * 整个方法是在UrlPicker中截取的方法。
	 * 按照标准标签来提取链接
	 * @param tagcontent
	 * @return
	 */
	private ArrayList pickUrlWithHref(ArrayList tagcontent) {

		if (tagcontent == null) {
			return null;
		}

		ArrayList result = new ArrayList();
		Iterator it;
		try {
			it = tagcontent.iterator();
		} catch (java.lang.NullPointerException e) {

			return null;
		}

		String str = "";

		L1:
		while (it.hasNext()) {

			str = (String) it.next();
			str = str.replace("HREF", "href").replace("\\", "");// 将转义字符去掉。测试！
			int indexOfhref = str.indexOf("href");//
			int indexOfEqu = str.indexOf("=", indexOfhref);

			if (indexOfhref == -1) {
				continue;
			}

			// 略去等号。
			int ind = indexOfEqu + 1;

			int inds;// 最后截取开始。
			int inde;// 截取结束。

			
			while (true) {

				
				
				try {
					
					str.charAt(ind);
				} catch (StringIndexOutOfBoundsException e) {//为了错误处理页面
					break L1;
				}
				if (str.charAt(ind) == ' ') {// 如果是空格的话。则略去。

					ind++;
					continue;

				} else if (str.charAt(ind) == '"') {

					inds = ind + 1;
					// System.out.println("截取开始符：" + str.charAt(inds));
					break;

				} else if (str.charAt(ind) == '\'') {
					inds = ind + 1;
					// System.out.println("截取开始符："+str.charAt(inds));
					break;

				} else {// 如果是=http://www.baidu.com这种没有引号的形式。
					inds = ind;
					break;
				}
			}
			
			 
		     if(inds==0){//处理异常了,发现有这种变态的格式URL:href"xueshujiaoliao.htm"
		    	 continue;
		     }
			
			if (str.charAt(inds - 1) == '"') {// 如果开始是"

				inde = str.indexOf("\"", inds);// 得到"的后续。得到截取终点。
				// System.out.println("截取终结符："+str.charAt(inde));

			} else if (str.charAt(inds - 1) == '\'') {

				inde = str.indexOf("'", inds);
				// System.out.println("截取终结符："+str.charAt(inde));

			} else {// 对应上面最后一种

				inde = str.indexOf(" ", inds);

				if (inde == -1) {// 如果是这种形式href=http://www.baidu.com

					inde = str.length();//
				}
			}
			//System.out.println(str);
			String gain=null;
			try {
				gain = str.substring(inds, inde);
			} catch (java.lang.StringIndexOutOfBoundsException e) {
				break L1;//如果出现了这种异常就<a class="hide" href="list.php?type=9
			}
			result.add(gain);
		}
		return result;
	}

	private String cut(String str) {

		String ss = str;
		if (str != null) {
			if (str.endsWith("/")) {
				int i = str.lastIndexOf("/");
				ss = str.substring(0, i);
			}
		}
		return ss;
	}

	public static void main(String[] args) {

		/*标准测试
		File htmlfile = new File(
				"C:\\Documents and Settings\\秋刀鱼的滋味\\桌面\\mypage\\p1");
		PageParser pp = new PageParser(htmlfile, "1", "成都理工大学");
		Page p = pp.getPage();
		p.printPage();

		File xmlfile = new File(
				"C:\\Documents and Settings\\秋刀鱼的滋味\\桌面\\实验\\pages.xml");
		DataWriter de = new DataWriter(xmlfile);
		de.writePage(p);
		*/
		File htmlfile1=new File("D:\\工作室收藏\\编程工作室\\JAVA区\\Java程序调试区\\搜索引擎\\workspace\\Work_Place\\成都理工大学\\Crawl Folder\\www.cdut.net\\PageDB\\PageDB3\\P6257");
		PageParser pp = new PageParser(htmlfile1, "1", "成都理工大学");
		Page p = pp.getPage();
		p.printPage();
		System.out.println("--------------------------------------------------");
		/*
		File htmlfile2=new File("D:\\工作室收藏\\编程工作室\\JAVA区\\Java程序调试区\\搜索引擎\\workspace\\Search engine\\Crawl Folder--cdut.edu.cn\\www.cdut.edu.cn\\PageDB\\PageDB2\\P53");
		PageParser kk=new PageParser(htmlfile2,"2","成都理工大学");
		Page pk=kk.getPage();
		pk.printPage();
		*/
	}  
}
